/*
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 *
 * Copyright @2008 the original author or authors.
 */
package com.bluestone.run;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.bluestone.core.Action;
import com.bluestone.core.ActionFactory;
import com.bluestone.core.Attributes;
import com.bluestone.core.Command;
import com.bluestone.core.Execute;
import com.bluestone.core.Project;
import com.bluestone.core.Proxy;
import com.bluestone.core.TestCase;
import com.bluestone.core.TestSuite;
import com.bluestone.proxy.HttpProxyServer;
import com.bluestone.report.ActionProxy;
import com.bluestone.report.ExportTool;
import com.bluestone.report.ProjectReportBean;
import com.bluestone.report.ProjectReportDataSource;
import com.bluestone.util.Util;

/**
 * 
 * @author <a href="mailto:bluestone.daniel.q@gmail.com">daniel.q</a> 
 */
public class RunManager {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String file = "./scripts/test.xml";
		if (args.length > 0) {
			file = args[0];
		}
		RunManager manager = new RunManager();
		manager.run(file);
	
	}

	private HashMap runElements = new HashMap();

	private String entryFile = null;

	private boolean flag = true;

	private Project project;
		
	public void run(String entryFile) {
		setEntryFile(entryFile);
		run();
	}
	
	public void run() {
		flag = true;
		runElements.clear();
		project = Util.getProject(entryFile);
		if (project == null)
			return;
		Util.info("run " + project.getName() + " start!");

		
		//cut project icon
		ActionFactory.createAction(ActionFactory.CHECKPROJECTACTION, null, null, null, null).execute();
		
        //check browser
		ActionFactory.createAction(ActionFactory.CHECKBROWSERACTION, null, null, null, null).execute();
		
		
		ProjectReport projectReport = new ProjectReport();
		ArrayList executes = project.getExecuteList();
		for (int i = 0; i < executes.size(); i++) {
			Execute execute = (Execute) executes.get(i);
			TestSuiteReport suiteReport = runExecute(execute);
			projectReport.getTestsuitereports().add(suiteReport);

			if (!suiteReport.getExecutecode()) {
				flag = false;
				break;
			}
		}

		projectReport.outputReport();

		jsReport();
		if (flag) {
			Util.info("run " + project.getName() + " sucessful!");
		} else {
			Util.info("run " + project.getName() + " failure!");
			Util.error("run " + project.getName() + " failure!");
		}
	}
	
	private void jsReport(){
		ProjectReportBean prb = ActionProxy.getProjectReportBean();
		Map parameters = new HashMap();
		parameters.put("ReportTitle", prb.getProjectName());			
		ExportTool.getInstance().exportToFile(project.getReportType(),project.getReportTemplate(), project.getReportFile(), new ProjectReportDataSource(prb), parameters);
	}

	private TestSuiteReport runExecute(Execute execute) {

		Util.info("run " + execute.getFile() + " start!");

		TestSuiteReport report = new TestSuiteReport();
		report.setReportFile(execute.getOutputFile());

		TestSuite testsuite = Util.getCurrentProject().getTestSuite(execute);
		if (testsuite == null) {
			Util.error(Util.ERROR1 + execute.getFile());
		}
		ArrayList testcases = testsuite.getTestcaseList();
		boolean needstandalone = false;
		
		for (int i = 0; i < testcases.size(); i++) {
			TestCase testcase = (TestCase) testcases.get(i);
			if(needstandalone){
				if(Attributes.FALSE.equalsIgnoreCase(testcase.getStandalone())){
					continue;
				}
			}
			if (testcase.getName().equalsIgnoreCase(Attributes.RESET)){
				continue;
			}
			TestCaseReport caseReport = runTestCase(testcase);
			report.addTestCaseReport(caseReport);
			if (!caseReport.getExecutecode()) {
				report.addFailureCase(testcase);
				runResetCase(testcase);
				needstandalone = true;
				Util.info("run "+testcase.getName()+" testcase failure!");
				Util.warn("run "+testcase.getName()+" testcase failure!");
			} else {
				report.addPassCase(testcase);
				needstandalone = false;
				Util.info("run "+testcase.getName()+" testcase sucessful!");
			}
			if (report.getFailureCount() > Integer.parseInt(project
					.getFailurecount())) {
				report.setExecutecode(false);
				break;
			}
		}
		if (report.getExecutecode()) {
			Util.info("run " + execute.getFile() + " sucessful!");
		} else {
			Util.info("run " + execute.getFile() + " failure!");
			Util.error("run " + execute.getFile() + " failure!");
		}
		return report;
	}

	private void runResetCase(TestCase testcase) {
		TestSuite testsuite = (TestSuite) testcase.getParent();
		ArrayList list = testsuite.getTestcaseList();
		for (int i = 0; i < list.size(); i++) {
			TestCase temp = (TestCase) list.get(i);
			if (temp.getName().equalsIgnoreCase("reset")) {
				Util.info("run reset testcase");
				TestCaseReport report = runTestCase(temp);
				if (report.getExecutecode()) {
					Util.info("run reset testcase sucessful!");
				} else {
					Util.info("run reset testcase failure!");
					Util.warn("run reset testcase failure!");
				}

			}
		}
	}

	private TestCaseReport runTestCase(TestCase testcase) {
		TestCaseReport report = new TestCaseReport();
		report.setId(testcase.getId());
		report.setExecuteResult("Pass");

		int retry = 1;
		Util.info("run testcase " + testcase.getName() + " start!");

		while (true) {

			ArrayList commands = testcase.getCommands();
			for (int i = 0; i < commands.size(); i++) {
				boolean commandFlag = true;
				Command command = (Command) commands.get(i);
				Util.info("run command " + command.getName() + " start!");
				ArrayList actions = command.getActions();
				boolean actionFlag = true;
				for (int j = 0; j < actions.size(); j++) {
					Action action = (Action) actions.get(j);
					if(!action.isValid()) {
						continue;
					}
					actionFlag = runAction(action);
					if (!actionFlag) {
						report.setExecuteResult("Fail");
						report.setExecutecode(false);
						report.setComment(action.toString());
						commandFlag = false;
						break;
					}
				}
				if (commandFlag) {
					Util.info("run command " + command.getName()
							+ " sucessful!");
				} else {
					Util.info("run command " + command.getName() + " failure!");
					Util.warn("run command " + command.getName() + " failure!");
				}

				if (!commandFlag) {
					report.setExecutecode(false);
					report.setExecuteResult("Fail");
					break;
				}
			}
			if (!report.getExecutecode()
					&& retry <= Integer.parseInt(project.getRetrycount())
					&& !testcase.getName().equalsIgnoreCase("reset")) {
				report.setExecutecode(true);
				report.setExecuteResult("Pass");
				Util.info("retry run testcase " + testcase.getName() + " "
						+ retry + " times");
				Util.warn("retry run testcase " + testcase.getName() + " "
						+ retry + " times");
				runResetCase(testcase);
				retry++;
			} else {
				break;
			}
		}
		if (report.getExecutecode()) {
			Util.info("run testcase " + testcase.getName() + " sucessful!");
		} else {
			Util.info("run testcase " + testcase.getName() + " failure!");
		}
		return report;
	}

	private boolean runAction(Action action) {
		boolean flag = ActionProxy.getActionProxy(action).execute();
		Util.info("run " + action.toString() + "-->" + flag);
		if(!flag){
			Util.warn("run " + action.toString() + "-->" + flag);
		}
		return flag;
	}

	public String getEntryFile() {
		return entryFile;
	}

	public void setEntryFile(String entryFile) {
		this.entryFile = entryFile;
	}

}
